/*
 * Project Name spring-boot-tools
 * File Name BaseServiceImpl
 * Package Name com.huxiaosu.tools.mybatis.base.service.impl
 * Create Time 2024/7/15
 * Create by name：liujie
 */
package com.huxiaosu.tools.mybatis.base.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huxiaosu.tools.mybatis.base.BaseDto;
import com.huxiaosu.tools.mybatis.base.PageInfo;
import com.huxiaosu.tools.mybatis.base.mapper.ToolsBaseMapper;
import com.huxiaosu.tools.mybatis.base.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Description
 *
 * @author liujie
 * @date 2024/7/15 17:47
 */
public abstract class BaseServiceImpl<Dao extends ToolsBaseMapper<Entity>, Dto, Entity> implements BaseService<Dto, Entity> {
    @Autowired
    protected Dao baseDao;

    @Override
    public Entity getById(Serializable id) {
        return baseDao.selectById(id);
    }

    @Override
    public int save(Entity t) {
        return baseDao.insert(t);
    }

    @Override
    public void update(Entity t) {
        baseDao.updateById(t);
    }

    @Override
    public void update(Dto d, Entity t) {

    }

    @Override
    public void deleteById(Serializable id) {
        Entity entity = baseDao.selectById(id);
        if (entity != null) {
            setDeleteMark(entity);
            deleteByEntity(entity);
        }

    }

    @Override
    public void deleteByEntity(Entity entity) {
        baseDao.deleteById(entity);
    }

    @Override
    public PageInfo<Entity> getList(Dto d) {
        BaseDto reqeustDto = (BaseDto) d;
        // todo 封装一下公用的 getList
        Page<Entity> pageQuery = new Page<Entity>(reqeustDto.getPage(), reqeustDto.getPageSize());
        String sortOrderField = StrUtil.toUnderlineCase(reqeustDto.getSortOrderField());
        OrderItem orderItem = OrderItem.asc(sortOrderField);
        if (reqeustDto.getSortOrder().equals("desc")) {
            orderItem = OrderItem.desc(sortOrderField);
        }
        pageQuery.addOrder(orderItem);
        QueryWrapper<Entity> queryWrapper = new QueryWrapper<>();
        Map<String, Object> mapParams = reqeustDto.getExtraData();
        if (mapParams != null && mapParams.size() > 0) {
            putDefaultParams(mapParams, queryWrapper);
            mapParams.forEach((key, value) -> {
                if (value instanceof String) {
                    // 取消掉通配符查询。
                    value = ((String) value).replace("%", "");
                    value = ((String) value).replace("'", "");
                    value = ((String) value).replace(",", "");
                    // 如果 key 中 包含 id 我们认为他不是模糊查询
                    if (key.equalsIgnoreCase("id") || key.equalsIgnoreCase("parentId") || key.contains("ParentId")) {
                        queryWrapper.eq(StrUtil.toUnderlineCase(key), value);
                    } else {
                        queryWrapper.like(StrUtil.toUnderlineCase(key), value);
                    }
                } else if (value instanceof Collection) {
                    // 值是一个 list
                    List<Object> queryList = (List<Object>) value;
                    queryWrapper.in(StrUtil.toUnderlineCase(key), queryList);
                } else {
                    queryWrapper.eq(StrUtil.toUnderlineCase(key), value);
                }
            });
        }
        IPage<Entity> tiPage = baseDao.selectPage(pageQuery, queryWrapper);
        PageInfo<Entity> tPageInfo = new PageInfo<>();
        tPageInfo.setTotalElements(tiPage.getTotal());
        tPageInfo.setContent(tiPage.getRecords());
        tPageInfo.setPage(reqeustDto.getPage());
        tPageInfo.setPageSize(reqeustDto.getPageSize());
        return tPageInfo;
    }

    @SuppressWarnings("Duplicates")
    protected void putDefaultParams(Map<String, Object> mapParams, QueryWrapper<Entity> queryWrapper) {
        mapParams.forEach((key, value) -> {
            // 判断参数
            // if (key.equals(""))
            // createAnd.add(criteriaBuilder.in(root.get("createTime")));
            if ("startTime".equals(key)) {
                // 时间范围查询 - 开始时间
                DateTime dateTime = DateUtil.parseDateTime(value + " 00:00:00");
                queryWrapper.ge(StrUtil.toUnderlineCase("createTime"), dateTime);
            } else if ("endTime".equals(key)) {
                // 时间范围查询 - 结束时间
                DateTime dateTime = DateUtil.parseDateTime(value + " 23:59:59");
                queryWrapper.le(StrUtil.toUnderlineCase("createTime"), dateTime);
            } /**
             * else if("groupName".equals(key)){
             * if(requestUri.contains("/system/groupManager")){
             * createAnd.add(criteriaBuilder.like(root.get(key), "%" + value + "%"));
             * }else{ createAnd.add(criteriaBuilder.like(root.get("groupInfo").get(key),
             * "%" + value + "%")); } }
             */
        });
        mapParams.remove("startTime");
        mapParams.remove("endTime");
        // mapParams.remove("groupName");
    }

    @Override
    public void deleteByIds(List<Serializable> ids) {
        List<Entity> entities = baseDao.selectBatchIds(ids);
        if(CollUtil.isNotEmpty(entities)){
            entities.forEach(this::setDeleteMark);
            baseDao.deleteByIds(entities);
        }

    }

    private void setDeleteMark(Entity entity) {
        try {
            // todo 请注意这个是标识软删除的字段
            Class<?> aClass = entity.getClass();
            Field deleteMark = ReflectUtil.getField(aClass, "deleteMark");
            ReflectUtil.setAccessible(deleteMark);
            ReflectUtil.setFieldValue(entity, deleteMark, true);
        } catch (Exception e) {
            // ignore
        }
    }
}